package cc.shacocloud.kotlin.tools.uitls

import java.lang.reflect.Array.*
import java.util.*
import java.util.function.Supplier

/**
 *
 * @author 思追(shaco)
 */
object Utils {

    const val ALLOWED_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz1234567890"

    const val INITIAL_HASH: Int = 7
    const val MULTIPLIER: Int = 31

    const val EMPTY_STRING: String = ""
    const val NULL_STRING: String = "null"
    const val ARRAY_START: String = "["
    const val ARRAY_END: String = "]"
    const val EMPTY_ARRAY: String = ARRAY_START + ARRAY_END
    const val ARRAY_ELEMENT_SEPARATOR: String = ", "
    val EMPTY_OBJECT_ARRAY: Array<Any> = arrayOf()

    /**
     * 生成随机字符串
     */
    fun randomStr(length: Int): String {
        return (1..length).map { ALLOWED_CHARS.random() }.joinToString(separator = "") { it.toString() }
    }

    /**
     * 获取默认类加载器
     */
    fun getDefaultClassLoader(): ClassLoader? {
        var cl: ClassLoader? = null
        try {
            cl = Thread.currentThread().contextClassLoader
        } catch (_: Throwable) {
        }
        if (cl == null) {
            cl = Utils::class.java.getClassLoader()
            if (cl == null) {
                try {
                    cl = ClassLoader.getSystemClassLoader()
                } catch (_: Throwable) {
                }
            }
        }
        return cl
    }

    /**
     * 将给定的数组（可能是基元数组）转换为对象数组（如果需要基元包装器对象）。
     *
     *
     * `null` 源值将转换为空的对象数组。
     *
     * @param source （可能原始的）数组
     * @return 相应的对象数组（从不 `null`）
     * @throws IllegalArgumentException 如果参数不是数组
     */
    @Suppress("UNCHECKED_CAST")
    fun Any?.toObjectArray(): Array<Any> {
        if (this == null) {
            return EMPTY_OBJECT_ARRAY
        }

        if (this is Array<*> && isArrayOf<Any>()) {
            return this as Array<Any>
        }

        require(javaClass.isArray) { "对象不是数组类型：$this" }

        val length = getLength(this)
        if (length == 0) {
            return EMPTY_OBJECT_ARRAY
        }
        val wrapperType = get(this, 0).javaClass
        val newArray = newInstance(wrapperType, length) as Array<Any>
        for (i in 0 until length) {
            newArray[i] = get(this, i)
        }
        return newArray
    }

    /**
     * 确定给定的对象是否相等，如果两个对象都是 `null`，则返回 `true`;如果只有一个对象为 `null`，则返回 `false`
     *
     * 将数组与 `Arrays.equals` 进行比较，根据数组元素而不是数组引用执行相等性检查。
     *
     * @param o1 第一个要比较的对象
     * @param o2 第二个要比较的对象
     * @return 给定对象是否相等
     * @see Object.equals
     * @see java.util.Arrays.equals
     */
    fun nullSafeEquals(o1: Any?, o2: Any?): Boolean {
        if (o1 === o2) {
            return true
        }
        if (o1 == null || o2 == null) {
            return false
        }
        if (o1 == o2) {
            return true
        }
        if (o1.javaClass.isArray && o2.javaClass.isArray) {
            return equals(o1, o2)
        }
        return false
    }

    /**
     * 如果值为空则使用提供者函数的值
     */
    fun <T : CharSequence?> T.emptyOrDefault(supplier: Supplier<T>): T {
        if (isNullOrEmpty()) {
            return supplier.get()
        }
        return this
    }

    /**
     * 将给定的数组与 `Arrays.equals` 进行比较，根据数组元素而不是数组引用执行相等性检查
     *
     * @param o1 第一个要比较的数组
     * @param o2 要比较的第二个数组
     * @return 给定对象是否相等
     * @see java.util.Arrays.equals
     */
    fun equals(o1: Any?, o2: Any?): Boolean {
        if (o1 is BooleanArray && o2 is BooleanArray) {
            return o1.contentEquals(o2 as BooleanArray?)
        } else if (o1 is ByteArray && o2 is ByteArray) {
            return o1.contentEquals(o2 as ByteArray?)
        } else if (o1 is CharArray && o2 is CharArray) {
            return o1.contentEquals(o2 as CharArray?)
        } else if (o1 is DoubleArray && o2 is DoubleArray) {
            return o1.contentEquals(o2 as DoubleArray?)
        } else if (o1 is FloatArray && o2 is FloatArray) {
            return o1.contentEquals(o2 as FloatArray?)
        } else if (o1 is IntArray && o2 is IntArray) {
            return o1.contentEquals(o2 as IntArray?)
        } else if (o1 is LongArray && o2 is LongArray) {
            return o1.contentEquals(o2 as LongArray?)
        } else if (o1 is ShortArray && o2 is ShortArray) {
            return o1.contentEquals(o2 as ShortArray?)
        } else if (o1 is Array<*> && o1.isArrayOf<Any>() && o2 is Array<*> && o2.isArrayOf<Any>()) {
            return (o1).contentEquals(o2)
        } else {
            return false
        }
    }


    /**
     * 作为给定对象的哈希代码返回;通常是 [Object.hashCode] 的值
     * 如果对象是数组，则此方法将委托给此类中数组的任何 `nullSafeHashCode` 方法
     * 如果对象为 `null`，则此方法返回 0
     *
     * @see Object.hashCode
     * @see .nullSafeHashCode
     * @see .nullSafeHashCode
     * @see .nullSafeHashCode
     * @see .nullSafeHashCode
     * @see .nullSafeHashCode
     * @see .nullSafeHashCode
     * @see .nullSafeHashCode
     * @see .nullSafeHashCode
     * @see .nullSafeHashCode
     */
    fun Any?.nullSafeHashCode(): Int {
        if (this == null) {
            return 0
        }
        if (this.javaClass.isArray) {
            if (this is Array<*> && this.isArrayOf<Any>()) {
                return nullSafeHashCode()
            }
            if (this is BooleanArray) {
                return nullSafeHashCode()
            }
            if (this is ByteArray) {
                return nullSafeHashCode()
            }
            if (this is CharArray) {
                return nullSafeHashCode()
            }
            if (this is DoubleArray) {
                return nullSafeHashCode()
            }
            if (this is FloatArray) {
                return nullSafeHashCode()
            }
            if (this is IntArray) {
                return nullSafeHashCode()
            }
            if (this is LongArray) {
                return nullSafeHashCode()
            }
            if (this is ShortArray) {
                return nullSafeHashCode()
            }
        }
        return this.hashCode()
    }

    /**
     * 根据指定数组的内容返回哈希代码。如果 `数组` 为 `null`，则此方法返回 0。
     */
    fun Array<*>?.nullSafeHashCode(): Int {
        if (this == null) {
            return 0
        }
        var hash: Int = INITIAL_HASH
        for (element in this) {
            hash = MULTIPLIER * hash + element.nullSafeHashCode()
        }
        return hash
    }

    /**
     * 根据指定数组的内容返回哈希代码。如果 `数组` 为 `null`，则此方法返回 0
     */
    fun BooleanArray?.nullSafeHashCode(): Int {
        if (this == null) {
            return 0
        }
        var hash: Int = INITIAL_HASH
        for (element in this) {
            hash = MULTIPLIER * hash + element.hashCode()
        }
        return hash
    }

    /**
     * 根据指定数组的内容返回哈希代码。如果 `数组` 为 `null`，则此方法返回 0
     */
    fun ByteArray?.nullSafeHashCode(): Int {
        if (this == null) {
            return 0
        }
        var hash: Int = INITIAL_HASH
        for (element in this) {
            hash = MULTIPLIER * hash + element
        }
        return hash
    }

    /**
     * 根据指定数组的内容返回哈希代码。如果 `数组` 为 `null`，则此方法返回 0
     */
    fun CharArray?.nullSafeHashCode(): Int {
        if (this == null) {
            return 0
        }
        var hash: Int = INITIAL_HASH
        for (element in this) {
            hash = MULTIPLIER * hash + element.code
        }
        return hash
    }

    /**
     * 根据指定数组的内容返回哈希代码。如果 `数组` 为 `null`，则此方法返回 0
     */
    fun DoubleArray?.nullSafeHashCode(): Int {
        if (this == null) {
            return 0
        }
        var hash: Int = INITIAL_HASH
        for (element in this) {
            hash = MULTIPLIER * hash + element.hashCode()
        }
        return hash
    }

    /**
     * 根据指定数组的内容返回哈希代码。如果 `数组` 为 `null`，则此方法返回 0
     */
    fun FloatArray?.nullSafeHashCode(): Int {
        if (this == null) {
            return 0
        }
        var hash: Int = INITIAL_HASH
        for (element in this) {
            hash = MULTIPLIER * hash + element.hashCode()
        }
        return hash
    }

    /**
     * 根据指定数组的内容返回哈希代码。如果 `数组` 为 `null`，则此方法返回 0
     */
    fun IntArray?.nullSafeHashCode(): Int {
        if (this == null) {
            return 0
        }
        var hash: Int = INITIAL_HASH
        for (element in this) {
            hash = MULTIPLIER * hash + element
        }
        return hash
    }

    /**
     * 根据指定数组的内容返回哈希代码。如果 `数组` 为 `null`，则此方法返回 0
     */
    fun LongArray?.nullSafeHashCode(): Int {
        if (this == null) {
            return 0
        }
        var hash: Int = INITIAL_HASH
        for (element in this) {
            hash = MULTIPLIER * hash + element.hashCode()
        }
        return hash
    }

    /**
     * 根据指定数组的内容返回哈希代码。如果 `数组` 为 `null`，则此方法返回 0
     */
    fun ShortArray?.nullSafeHashCode(): Int {
        if (this == null) {
            return 0
        }
        var hash: Int = INITIAL_HASH
        for (element in this) {
            hash = MULTIPLIER * hash + element
        }
        return hash
    }

    /**
     * 返回指定对象的一个字符串表示
     */
    fun Any?.nullSafeToString(): String {
        if (this == null) {
            return NULL_STRING
        }

        if (this is String) {
            return this
        }
        if (this is Array<*> && this.isArrayOf<Any>()) {
            return nullSafeToString()
        }
        if (this is BooleanArray) {
            return nullSafeToString()
        }
        if (this is ByteArray) {
            return nullSafeToString()
        }
        if (this is CharArray) {
            return nullSafeToString()
        }
        if (this is DoubleArray) {
            return nullSafeToString()
        }
        if (this is FloatArray) {
            return nullSafeToString()
        }
        if (this is IntArray) {
            return nullSafeToString()
        }
        if (this is LongArray) {
            return nullSafeToString()
        }
        if (this is ShortArray) {
            return nullSafeToString()
        }

        return toString()
    }

    /**
     * 返回指定数组内容的一个字符串表示
     */
    fun Array<*>?.nullSafeToString(): String {
        if (this == null) {
            return NULL_STRING
        }
        val length = this.size
        if (length == 0) {
            return EMPTY_ARRAY
        }
        val stringJoiner = StringJoiner(
            ARRAY_ELEMENT_SEPARATOR,
            ARRAY_START,
            ARRAY_END
        )
        for (o in this) {
            stringJoiner.add(o.toString())
        }
        return stringJoiner.toString()
    }

    /**
     * 返回指定数组内容的一个字符串表示
     */
    fun BooleanArray?.nullSafeToString(): String {
        if (this == null) {
            return NULL_STRING
        }
        val length = this.size
        if (length == 0) {
            return EMPTY_ARRAY
        }
        val stringJoiner = StringJoiner(
            ARRAY_ELEMENT_SEPARATOR,
            ARRAY_START,
            ARRAY_END
        )
        for (b in this) {
            stringJoiner.add(b.toString())
        }
        return stringJoiner.toString()
    }

    /**
     * 返回指定数组内容的一个字符串表示
     */
    fun ByteArray?.nullSafeToString(): String {
        if (this == null) {
            return NULL_STRING
        }
        val length = this.size
        if (length == 0) {
            return EMPTY_ARRAY
        }
        val stringJoiner = StringJoiner(
            ARRAY_ELEMENT_SEPARATOR,
            ARRAY_START,
            ARRAY_END
        )
        for (b in this) {
            stringJoiner.add(b.toString())
        }
        return stringJoiner.toString()
    }

    /**
     * 返回指定数组内容的一个字符串表示
     */
    fun CharArray?.nullSafeToString(): String {
        if (this == null) {
            return NULL_STRING
        }
        val length = this.size
        if (length == 0) {
            return EMPTY_ARRAY
        }
        val stringJoiner = StringJoiner(
            ARRAY_ELEMENT_SEPARATOR,
            ARRAY_START,
            ARRAY_END
        )
        for (c in this) {
            stringJoiner.add("'$c'")
        }
        return stringJoiner.toString()
    }

    /**
     * 返回指定数组内容的一个字符串表示
     */
    fun DoubleArray?.nullSafeToString(): String {
        if (this == null) {
            return NULL_STRING
        }
        val length = this.size
        if (length == 0) {
            return EMPTY_ARRAY
        }
        val stringJoiner = StringJoiner(
            ARRAY_ELEMENT_SEPARATOR,
            ARRAY_START,
            ARRAY_END
        )
        for (d in this) {
            stringJoiner.add(d.toString())
        }
        return stringJoiner.toString()
    }

    /**
     * 返回指定数组内容的一个字符串表示
     */
    fun FloatArray?.nullSafeToString(): String {
        if (this == null) {
            return NULL_STRING
        }
        val length = this.size
        if (length == 0) {
            return EMPTY_ARRAY
        }
        val stringJoiner = StringJoiner(
            ARRAY_ELEMENT_SEPARATOR,
            ARRAY_START,
            ARRAY_END
        )
        for (f in this) {
            stringJoiner.add(f.toString())
        }
        return stringJoiner.toString()
    }

    /**
     * 返回指定数组内容的一个字符串表示
     */
    fun IntArray?.nullSafeToString(): String {
        if (this == null) {
            return NULL_STRING
        }
        val length = this.size
        if (length == 0) {
            return EMPTY_ARRAY
        }
        val stringJoiner = StringJoiner(
            ARRAY_ELEMENT_SEPARATOR,
            ARRAY_START,
            ARRAY_END
        )
        for (i in this) {
            stringJoiner.add(i.toString())
        }
        return stringJoiner.toString()
    }

    /**
     * 返回指定数组内容的一个字符串表示
     */
    fun LongArray?.nullSafeToString(): String {
        if (this == null) {
            return NULL_STRING
        }
        val length = this.size
        if (length == 0) {
            return EMPTY_ARRAY
        }
        val stringJoiner = StringJoiner(
            ARRAY_ELEMENT_SEPARATOR,
            ARRAY_START,
            ARRAY_END
        )
        for (l in this) {
            stringJoiner.add(l.toString())
        }
        return stringJoiner.toString()
    }

    /**
     * 返回指定数组内容的一个字符串表示
     */
    fun ShortArray?.nullSafeToString(): String {
        if (this == null) {
            return NULL_STRING
        }

        val length = size
        if (length == 0) {
            return EMPTY_ARRAY
        }
        val stringJoiner = StringJoiner(
            ARRAY_ELEMENT_SEPARATOR,
            ARRAY_START,
            ARRAY_END
        )
        for (s in this) {
            stringJoiner.add(s.toString())
        }
        return stringJoiner.toString()
    }


}